home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / mail / smail-3.1.28 / src / main.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-09-20  |  34.1 KB  |  1,394 lines

  1. /* @(#)src/main.c    1.24 9/20/92 12:54:53 */
  2.  
  3. /*
  4.  *    Copyright (C) 1987, 1988 Ronald S. Karr and Landon Curt Noll
  5.  *    Copyright (C) 1992  Ronald S. Karr
  6.  * 
  7.  * See the file COPYING, distributed with smail, for restriction
  8.  * and warranty information.
  9.  */
  10.  
  11. /*
  12.  * main.c:
  13.  *    process arguments, configure environment and process
  14.  *    messages.
  15.  *
  16.  *    external functions: main, initialize_state, process_args
  17.  */
  18. #include <stdio.h>
  19. #include <ctype.h>
  20. #include <sys/types.h>
  21. #include <sys/stat.h>
  22. #include <errno.h>
  23. #include <pwd.h>
  24. #include <signal.h>
  25. #include "defs.h"
  26. #if defined(POSIX_OS) || !defined(UNIX_BSD)
  27. # include <time.h>
  28. #else
  29. # include <sys/time.h>
  30. #endif    /* UNIX_BSD */
  31. #if defined(HAVE_RLIMIT)
  32. # include <sys/resource.h>
  33. #endif    /* HAVE_RLIMIT */
  34. #ifdef    UNIX_AIX3
  35. # include <sys/id.h>
  36. #endif    /* UNIX_AIX3 */
  37. #include "config.h"
  38. #include "smail.h"
  39. #include "dys.h"
  40. #include "addr.h"
  41. #include "hash.h"
  42. #include "main.h"
  43. #include "log.h"
  44. #include "transport.h"
  45. #include "child.h"
  46. #include "exitcodes.h"
  47. #include "smailconf.h"
  48. #include "alloc.h"
  49. #ifndef DEPEND
  50. # include "extern.h"
  51. # include "debug.h"
  52. # include "error.h"
  53. #endif
  54.  
  55. /* exported variables */
  56. int islocal;                /* TRUE if mail originated locally */
  57. int exitvalue;                /* call exit with this value */
  58. char *program;                /* argv[0] from main */
  59. char *sender;                /* sender of message */
  60. char *local_sender;            /* local sender of message */
  61. int error_sender;            /* TRUE if special sender <> given */
  62. char *sender_name;            /* full name of sender */
  63. enum op_mode operation_mode;        /* mode of operation */
  64. int debug = 0;                /* debugging level, 0 is off */
  65. int dont_deliver = FALSE;        /* if TRUE, don't actually deliver */
  66. int process_queue;            /* process spooled files */
  67. unsigned queue_interval;        /* process queues at this interval */
  68. int hop_count;                /* hop count so far for message */
  69. int do_aliasing;            /* do aliasing for local addresses */
  70. int extract_addresses;            /* get recipients from header */
  71. int me_too;                /* sender allowed in aliases */
  72. enum er_proc error_processing;        /* method of displaying errors */
  73. enum dot_usage dot_usage;        /* how do we treat . on input */
  74. enum deliver_mode
  75.     deliver_mode = DELIVER_DEFAULT;    /* foreground, background or queued */
  76. struct addr *recipients;        /* list of recipient addresses */
  77. char *primary_name;            /* primary local name from hostnames */
  78. FILE *errfile = NULL;            /* file to write debug messages to */
  79. int real_uid;                /* saved real uid before ruid setup */
  80. enum prog_type prog_type;        /* type of program we are running as */
  81. char **save_argv;            /* saved pointer to arguments */
  82. int some_deferred_addrs;        /* don't unlink spool file */
  83.                     /* as some addrs were deferred */
  84. int prog_euid;                /* effective uid of program */
  85. int prog_egid;                /* effective gid of program */
  86. int force_zero_exitvalue = FALSE;    /* if TRUE always exit with status 0 */
  87. int call_defer_message;            /* if TRUE must call defer_message() */
  88. int sender_is_trusted;            /* TRUE if sender is a trusted user */
  89. char *sender_host = NULL;        /* name of sender's host */
  90. char *sender_host_addr = NULL;        /* inet address of sender's host */
  91. char *sender_proto = NULL;        /* name of sender's sending protocol */
  92. char *sender_program = NULL;        /* name of program that spooled msg */
  93. char *smtp_service_name = NULL;        /* smtp service name from -oX */
  94. #ifdef GLOTZNET
  95. char *glotzhost;
  96. char *getenv();
  97. #endif /* GLOTZNET */
  98.  
  99. /* functions local to this file */
  100. static void panic_if_null();
  101. static void rmail_panic();
  102. static char *escape_newline();
  103.  
  104. /* variables local to this file */
  105. static int report_memory_usage = FALSE;    /* if TRUE, report sbrk(0) when done */
  106. static char *arg_second_config_file = NULL; /* second config set by args */
  107. static char *arg_director_file = NULL;    /* director file set by args */
  108. static char *arg_router_file = NULL;    /* router file set by args */
  109. static char *arg_transport_file = NULL;    /* transport file set by args */
  110. static char *arg_qualify_file = NULL;   /* domain qualification file set by args */
  111. static char *arg_retry_file = NULL;     /* address retry file set by args */
  112. static char *arg_smail_lib_dir = NULL;    /* smail lib dir set by args */
  113. static char *arg_alias_file = NULL;    /* alias file set by -oA */
  114. static char *arg_debug_file = NULL;    /* debug file, defaulting to stderr */
  115.  
  116. extern int errno;
  117.  
  118.  
  119. /*
  120.  * main - what to do after being exec'd
  121.  *
  122.  * main decodes the argument list and then performs specified action
  123.  */
  124. /*ARGSUSED*/
  125. void
  126. main(argc, argv)
  127.     int argc;                /* count of arguments passed */
  128.     char **argv;            /* vector of arguments */
  129. {
  130.     char *save_config_file = config_file;
  131.     struct stat statbuf;
  132.     char *error;
  133.     char *utilargs[10];
  134.     int child;
  135.     FILE *new_errfile;
  136.  
  137.     save_argv = argv;
  138.  
  139. #ifdef GLOTZNET
  140.     glotzhost = getenv("GLOTZHOST");
  141.     if (glotzhost == NULL) {
  142.     glotzhost = "namei";
  143.     }
  144. #endif /* GLOTZNET */
  145.  
  146.     /* set up the file for interactive error and debug messages */
  147.     if (!errfile) {
  148.     /* is stderr a valid file descriptor? */
  149.     if (fstat(2, &statbuf) >= 0) {
  150.         /* yes, use stderr */
  151.         errfile = stderr;
  152.     } else {
  153.         /* no, can't output to stderr */
  154.         errfile = NULL;
  155.     }
  156.     }
  157.     /* close file descriptors left open by others */
  158.     close_all();
  159.  
  160.     /*
  161.      * get the basename for the program
  162.      */
  163.     program = rindex(*argv, '/');
  164.     if (program == NULL) {
  165.     program = *argv;
  166.     } else {
  167.     program++;
  168.     }
  169.     argv++;
  170.     sender_program = program;
  171.  
  172. #ifdef    UNIX_SCO
  173.     /* if we don't have a login id, assume one */
  174.     if (getluid() == -1)
  175.     setluid(0);
  176. #endif    /* UNIX_SCO */
  177.  
  178. #ifdef    UNIX_AIX3
  179.     /* if we don't have a login id, assume one */
  180.     if (getuidx(ID_LOGIN) == -1)
  181.     setuidx(ID_LOGIN, 0);
  182. #endif    /* UNIX_AIX3 */
  183.  
  184. #ifdef    HAVE_SETGROUPS
  185.     /* clear out all extra groups.  We don't want to have to deal with them */
  186.     {
  187.     gid_t dummy;
  188.     (void) setgroups(0, &dummy);
  189.     }
  190. #endif    /* HAVE_SETGROUPS */
  191.  
  192.     /* get rid of any limits that might affect operation */
  193. #if defined(HAVE_ULIMIT) && !defined(HAVE_RLIMIT)
  194.     /* kill limits on file size */
  195.     (void) ulimit(2, ((long)1 << (BITS_PER_LONG - 2))/512);
  196. #endif    /* HAVE_ULIMIT && !defined(HAVE_RLIMIT) */
  197.  
  198.     /* always get a write error for a SIGPIPE, rather than dying */
  199.     (void) signal(SIGPIPE, SIG_IGN);
  200.  
  201. #if defined(HAVE_RLIMIT)
  202.     /* kill limits on file size, cpu, data segment, and unreasonable
  203.      * limits on stack size */
  204.     {
  205.     struct rlimit rl;
  206.  
  207.     rl.rlim_cur = RLIM_INFINITY;
  208.     rl.rlim_max = RLIM_INFINITY;
  209.     (void) setrlimit(RLIMIT_CPU, &rl);
  210.     (void) setrlimit(RLIMIT_FSIZE, &rl);
  211. #if defined(DATA_RLIMIT)
  212.     rl.rlim_cur = DATA_RLIMIT;
  213. #endif    /* DATA_RLIMIT */
  214.     (void) setrlimit(RLIMIT_DATA, &rl);
  215. #if defined(STACK_RLIMIT)
  216.     rl.rlim_cur = STACK_RLIMIT;
  217. #endif    /* STACK_RLIMIT */
  218.     (void) setrlimit(RLIMIT_STACK, &rl);
  219.     }
  220. #endif    /* HAVE_RLIMIT */
  221.  
  222. #if    defined(UNIX_AIX) && !defined(NO_AIX_CORE_DUMP)
  223.     /* On a segmentation fault or bus error, we need a full core dump.  */
  224.     {
  225.     struct sigaction act;
  226.  
  227.     act.sa_handler = SIG_DFL;
  228.     sigemptyset(&act.sa_mask);
  229.     act.sa_flags = SA_FULLDUMP;
  230.     sigaction(SIGSEGV, &act, (struct sigaction *)NULL);
  231.     sigaction(SIGBUS, &act, (struct sigaction *)NULL);
  232.     }
  233. #endif    /* UNIX_AIX && !NO_AIX_CORE_DUMP */
  234.  
  235.     /* Xenix systems must have TZ in the environment */
  236. #ifdef    REQUIRE_TZ
  237.     /* if no timezone specified, assume GMT */
  238.     if (getenv("TZ") == NULL) {
  239.     (void) putenv("TZ=GMT0");
  240.     }
  241. #endif
  242.  
  243.     /* we will always be supplying exactly the mode we want */
  244.     (void) umask(0);
  245.  
  246.     /* set the program type based on the program's basename */
  247.     prog_type = PROG_SMAIL;
  248.     if (EQ(program, "rmail")) {
  249.     prog_type = PROG_RMAIL;
  250.     } else if (EQ(program, "pathto")) {
  251.     prog_type = PROG_PATHTO;
  252.     } else if (EQ(program, "optto")) {
  253.     prog_type = PROG_OPTTO;
  254.     } else if (EQ(program, "uupath")) {
  255.     prog_type = PROG_UUPATH;
  256.     } else if (EQ(program, "newaliases")) {
  257.     prog_type = PROG_NEWALIASES;
  258.     } else if (EQ(program, "smailconf")) {
  259.     prog_type = PROG_SMAILCONF;
  260.     } else if (EQ(program, "mailq")) {
  261.     prog_type = PROG_MAILQ;
  262.     } else if (EQ(program, "runq")) {
  263.     prog_type = PROG_RUNQUEUE;
  264.     } else if (EQ(program, "smtpd")) {
  265.     /*
  266.      * if there is no file on stdout, then dup stdin to stdout.
  267.      * This is done because processes started from inetd will have
  268.      * fd 0 set to the socket, but fd 1 will not be set.  It will
  269.      * need to be dup'd for this to work.
  270.      */
  271.     if (fstat(1, &statbuf) < 0) {
  272.         dup2(0, 1);
  273.     }
  274.     prog_type = PROG_SMTPD;
  275.     } else if (EQ(program, "rsmtp")) {
  276.     prog_type = PROG_RSMTP;
  277.     } else if (EQ(program, "rogue") || EQ(program, "hack")) {
  278.     prog_type = PROG_ROGUE;
  279.     } else if (EQ(program, "..execmail") || EQ(program, "execmail")) {
  280.     prog_type = PROG_EXECMAIL;
  281.     }
  282.  
  283.     /* initialize per-message state information */
  284.     initialize_state();
  285.  
  286.     /* set state information which depends on program type */
  287.     if (prog_type == PROG_NEWALIASES) {
  288.     operation_mode = REBUILD_ALIASES;
  289.     } else if (prog_type == PROG_SMAILCONF) {
  290.     operation_mode = FREEZE_CONFIG;
  291.     } else if (prog_type == PROG_MAILQ) {
  292.     operation_mode = PRINT_QUEUE;
  293.     } else if (prog_type == PROG_RSMTP) {
  294.     operation_mode = BATCH_SMTP_MODE;
  295.     } else if (prog_type == PROG_SMTPD) {
  296.     operation_mode = SMTP_MODE;
  297.     } else if (prog_type == PROG_PATHTO) {
  298.     pathto(argv);
  299.     } else if (prog_type == PROG_OPTTO) {
  300.     optto(argv);
  301.     } else if (prog_type == PROG_UUPATH) {
  302.     uupath(argv);
  303.     } else if (prog_type == PROG_RMAIL) {
  304.     dot_usage = NO_DOT_PROTOCOL;
  305.     }
  306.  
  307.     /* process the args given by the user */
  308.     process_args(argv);
  309.  
  310.     if (prog_type == PROG_RUNQUEUE) {
  311.     if (operation_mode == MODE_DEFAULT ||
  312.         operation_mode == DAEMON_MODE)
  313.     {
  314.         process_queue = TRUE;
  315.     }
  316.     }
  317.     if (operation_mode == MODE_DEFAULT) {
  318.     /*
  319.      * when performing a queue run, no other operations are
  320.      * performed, by default.  Currently no other operations
  321.      * are allowed, either, though this may change in the
  322.      * future.
  323.      */
  324.     if (prog_type == PROG_RUNQUEUE || process_queue) {
  325.         operation_mode = NOOP_MODE;
  326.     } else {
  327.         operation_mode = DELIVER_MAIL;
  328.     }
  329.     }
  330.  
  331.     if (prog_type == PROG_ROGUE) {
  332.     operation_mode = ROGUE_MODE;
  333.     }
  334.  
  335.     if (config_file != save_config_file || arg_second_config_file ||
  336.     arg_director_file || arg_router_file || arg_transport_file ||
  337.     arg_qualify_file || arg_retry_file || arg_smail_lib_dir ||
  338.     arg_alias_file || operation_mode == REBUILD_ALIASES)
  339.     {
  340.     /*
  341.      * a config_file was set, or unset from the command args
  342.      * then watch out for set-uid execs;  i.e., go back to
  343.      * the real uid under which we were invoked.
  344.      */
  345.     setgid(getgid());
  346.     setuid(getuid());
  347.     }
  348.  
  349.     /* read in the config files, if they exists */
  350.     if (arg_smail_lib_dir) {
  351.     smail_lib_dir = arg_smail_lib_dir;
  352.     }
  353.     error = read_config_file(config_file = make_lib_fn(config_file));
  354.     /* we need to set this again, in case it was changed in the config files */
  355.     if (arg_smail_lib_dir) {
  356.     smail_lib_dir = arg_smail_lib_dir;
  357.     }
  358.     if (arg_second_config_file) {
  359.     second_config_file = arg_second_config_file;
  360.     }
  361.     second_config_file = make_lib_fn(second_config_file);
  362.     if (error == NULL && second_config_file) {
  363.     error = read_config_file(second_config_file);
  364.     }
  365.     /* we need to set this again, in case it was changed in the config files */
  366.     if (arg_smail_lib_dir) {
  367.     smail_lib_dir = arg_smail_lib_dir;
  368.     }
  369.     if (arg_smail_lib_dir) {
  370.     smail_lib_dir = arg_smail_lib_dir;
  371.     }
  372.     if (arg_director_file) {
  373.     director_file = arg_director_file;
  374.     }
  375.     if (arg_router_file) {
  376.     router_file = arg_router_file;
  377.     }
  378.     if (arg_transport_file) {
  379.     transport_file = arg_transport_file;
  380.     }
  381.     if (arg_qualify_file) {
  382.     qualify_file = arg_qualify_file;
  383.     }
  384.     if (arg_retry_file) {
  385.     retry_file = arg_retry_file;
  386.     }
  387.     /* get the config file names within the lib directory */
  388.     director_file = make_lib_fn(director_file);
  389.     router_file = make_lib_fn(router_file);
  390.     transport_file = make_lib_fn(transport_file);
  391.     method_dir = make_lib_fn(method_dir);
  392.     qualify_file = make_lib_fn(qualify_file);
  393.     retry_file = make_lib_fn(retry_file);
  394.     copying_file = make_lib_fn(copying_file);
  395.     smail = make_lib_fn(smail);
  396.  
  397.     if (error) {
  398.     /*
  399.      * error in the config file: not a good thing.
  400.      *
  401.      * Revert back to the initial values of vital attributes,
  402.      * and set queue_only to avoid trying to perform delivery
  403.      * with a potentially bad configuration.
  404.      */
  405.     max_message_size = MAX_MESSAGE_SIZE;
  406.     log_fn = LOGFILE;
  407.     panic_fn = PANIC_LOG;
  408.     cons_fn = CONSOLE;
  409.     spool_dirs = SPOOL_DIRS;
  410.     spool_mode = SPOOL_MODE;
  411.     lock_mode = LOCK_MODE;
  412.     log_mode = LOG_MODE;
  413.     message_log_mode = MESSAGE_LOG_MODE;
  414.     message_bufsiz = MESSAGE_BUF_SIZE;
  415.     queue_only = TRUE;
  416.  
  417.     /*
  418.      * if we are not actually going to be reading in messages,
  419.      * then panic.  Also, allow some trivial operations.
  420.      */
  421.     switch (operation_mode) {
  422.     case PRINT_QUEUE:
  423.     case PRINT_VERSION:
  424.     case SMTP_MODE:
  425.     case BATCH_SMTP_MODE:
  426.     case DELIVER_MAIL:
  427.     case PRINT_VARS_MODE:
  428.     case REBUILD_ALIASES:
  429.         write_log(LOG_TTY|LOG_PANIC, "%s", error);
  430.         break;
  431.  
  432.     default:
  433.         panic(EX_OSFILE, "%s", error);
  434.         /*NOTREACHED*/
  435.     }
  436.     }
  437.  
  438.     /*
  439.      * change error file to debugging file from -D option, if any
  440.      */
  441.  
  442.     if (arg_debug_file) {
  443.     new_errfile = fopen(arg_debug_file, "a");
  444.     if (new_errfile == NULL) {
  445.         write_log(LOG_TTY, "Warning: Cannot open debug file %s: %s\n",
  446.               arg_debug_file, strerrno(errno));
  447.         arg_debug_file = NULL;
  448.     } else {
  449.         errfile = new_errfile;
  450.         fprintf(errfile, "\n%s: Debugging started: pid=%ld\n\n",
  451.             program, (long)getpid());
  452.     }
  453.     }
  454.  
  455.     /*
  456.      * read in the transport, router and director files, if needed
  457.      *
  458.      * NOTE: if queue_only is FALSE and mode is DELIVER_MAIL,
  459.      *         we will need to read these files, though do this later
  460.      *         to avoid wasting time on it before the spool file is
  461.      *         created.
  462.      */
  463.     switch (operation_mode) {
  464.     case NOOP_MODE:
  465.     case DAEMON_MODE:
  466.     /*
  467.      * stat our binary so we can see if it has been touched later
  468.      */
  469.     if (stat(smail, &statbuf) < 0) {
  470.         panic(EX_SOFTWARE, "main: bad stat of smail binary %s", smail);
  471.     } else {
  472.         add_config_stat(smail, &statbuf);
  473.     }
  474.     /*FALL THROUGH*/
  475.  
  476.     case TEST_MODE:
  477.     case VERIFY_ADDRS:
  478.     case BATCH_SMTP_MODE:
  479.     case SMTP_MODE:
  480.     if ((error = read_transport_file()) ||
  481.         (error = read_router_file()) ||
  482.         (error = read_director_file()) ||
  483.         (error = read_qualify_file()) ||
  484.         (error = read_retry_file()))
  485.     {
  486.         panic(EX_OSFILE, "%s", error);
  487.     }
  488.     break;
  489.     }
  490.  
  491.     switch (operation_mode) {
  492.     case NOOP_MODE:
  493.     case DAEMON_MODE:
  494.     case TEST_MODE:
  495.     cache_directors();
  496.     cache_routers();
  497.     cache_transports();
  498.     break;
  499.     }
  500.  
  501.     /*
  502.      * Save away the real uid and set the real to the effective.
  503.      * After this point, the real uid is no longer at all interesting.
  504.      * In BSD, if the mailer runs as root, we can now freely set the
  505.      * real or effective uid to whatever we want without worrying about
  506.      * swapping them.  Also, if the mailer runs as a user other than
  507.      * root, we no longer have to worry about child processes being
  508.      * able to do a setuid(getuid) to get root priveledges when root
  509.      * sends mail.
  510.      */
  511.     real_uid = getuid();
  512.     prog_euid = geteuid();        /* keep a copy of the effictive id's */
  513.     prog_egid = getegid();
  514.     setuid(prog_euid);
  515.     setgid(prog_egid);
  516.  
  517.     /*
  518.      * If the current effective UID does not match the required ID,
  519.      * then mail can be queued (if that succeeds), but mail will
  520.      * not be delivered.  This only applies when receiving mail,
  521.      * and is ignored when running through the queue from a
  522.      * queue run daemon.
  523.      */
  524. #ifdef REQUIRED_EUID
  525.     if (prog_euid != REQUIRED_EUID)
  526.         queue_only = TRUE;
  527. #endif
  528.  
  529.     /*
  530.      * error processing can be other than TERMINAL only for
  531.      * mail delivery modes
  532.      */
  533.     switch (operation_mode)
  534.     {
  535.     case DELIVER_MAIL:
  536.     case NOOP_MODE:
  537.     case DAEMON_MODE:
  538.     case SMTP_MODE:
  539.     case BATCH_SMTP_MODE:
  540.     if (error_processing == ERROR_DEFAULT) {
  541.         error_processing = MAIL_BACK;
  542.     }
  543.     break;
  544.  
  545.     default:
  546.     error_processing = TERMINAL;
  547.     break;
  548.     }
  549.  
  550.     if (process_queue &&
  551.     operation_mode != NOOP_MODE &&
  552.     operation_mode != DAEMON_MODE)
  553.     {
  554.     if (errfile) {
  555.         fprintf(errfile,
  556.             "%s: operation mode not compatible with queue runs\n",
  557.             program);
  558.     }
  559.     exit(EX_USAGE);
  560.     }
  561.  
  562.     /*
  563.      * setup the delivery mode used for delivering new messages
  564.      */
  565.     if (deliver_mode == DELIVER_DEFAULT) {
  566.     /*
  567.      * if not set explicity in the arguments, key off the first
  568.      * letter of the configuration parameter
  569.      */
  570.     switch (delivery_mode_string[0]) {
  571.     case 'f':
  572.         deliver_mode = FOREGROUND;
  573.         break;
  574.     case 'b':
  575.         deliver_mode = BACKGROUND;
  576.         break;
  577.     default:
  578.         deliver_mode = QUEUE_MESSAGE;
  579.         break;
  580.     }
  581.     }
  582.  
  583.     /*
  584.      * if debugging to standard error, then don't do background delivery.
  585.      * Otherwise, we might continue writing to standard error after the
  586.      * main process has exited.
  587.      */
  588.     if (debug && arg_debug_file == NULL && deliver_mode == BACKGROUND)
  589.     deliver_mode = FOREGROUND;
  590.  
  591.     /*
  592.      * invoke the correct mode of operation
  593.      */
  594.     switch (operation_mode) {
  595.     case TEST_MODE:            /* test addresses from stdin */
  596.     test_addresses();        /* read addrs from stdin, for tests */
  597.     break;
  598.  
  599.     case NOOP_MODE:            /* generally, this means run queue */
  600.     dont_deliver = FALSE;        /* it is too dangerous to allow this */
  601.     noop_mode();
  602.     break;
  603.  
  604.     case PRINT_QUEUE:            /* print the mail queue */
  605.     print_queue();
  606.     break;
  607.  
  608.     case PRINT_VERSION:
  609.     print_version();
  610.     break;
  611.  
  612.     case VERIFY_ADDRS:            /* spit out resoved addresses */
  613.     if (recipients == NULL && !extract_addresses) {
  614.         if (errfile) {
  615.         (void) fprintf(errfile, "Usage: %s [flags] address...\n",
  616.                    program);
  617.         }
  618.         exitvalue = EX_USAGE;
  619.         break;
  620.     }
  621.     verify_addresses();
  622.     break;
  623.  
  624.     case SMTP_MODE:            /* read SMTP requests on stdin */
  625.     smtp_mode(stdin, stdout);
  626.     break;
  627.  
  628.     case BATCH_SMTP_MODE:        /* batched SMTP requests on stdin */
  629.     smtp_mode(stdin, (FILE *)NULL);
  630.     break;
  631.  
  632.     case DAEMON_MODE:            /* be a daemon waiting for requests */
  633.     dont_deliver = FALSE;        /* it is too dangerous to allow this */
  634.     daemon_mode();
  635.     break;
  636.  
  637.     case FREEZE_CONFIG:            /* freeze the configuration */
  638.     if (errfile) {
  639.         (void) fprintf(errfile,
  640.                "%s: operation not currently supported\n",
  641.                program);
  642.     }
  643.     exitvalue = EX_UNAVAILABLE;
  644.     break;
  645.  
  646.     case DELIVER_MAIL:            /* deliver to all addresses found */
  647.     if (recipients == NULL && !extract_addresses) {
  648.         if (errfile) {
  649.         (void) fprintf(errfile, "Usage: %s [flags] address...\n",
  650.                    program);
  651.         }
  652.         exitvalue = EX_USAGE;
  653.         break;
  654.     }
  655.  
  656.     perform_deliver_mail();
  657.     break;
  658.  
  659.     case ROGUE_MODE:            /* print a rogue tombstone */
  660.     silly();
  661.     break;
  662.  
  663.     case COPYING_MODE:
  664.     print_copying_file();
  665.     break;
  666.  
  667.     case PRINT_VARS_MODE:
  668.     print_variables();
  669.     break;
  670.  
  671.     case REBUILD_ALIASES:
  672.  
  673.     /*
  674.      * if an alias file was set explicitly with -oA, then build
  675.      * a DBM file appropriate for use with YP.  Otherwise, just
  676.      * call mkaliases to rebuild the default alias file.
  677.      */
  678.  
  679.     if (smail_util_dir == NULL) {
  680.         if (errfile) {
  681.         fprintf(errfile, "%s: smail_util_dir attribute not set, -bi operation not supported\n", program);
  682.         }
  683.         exit(EX_UNAVAILABLE);
  684.     }
  685.     if (arg_alias_file) {
  686.         utilargs[0] = xprintf("%s/mkdbm", smail_util_dir);
  687.         utilargs[1] = "-v";
  688.         utilargs[2] = "-y";
  689.         utilargs[3] = "-o";
  690.         utilargs[4] = arg_alias_file;
  691.         utilargs[5] = arg_alias_file;
  692.         utilargs[6] = NULL;
  693.     } else {
  694. #ifdef SHELL_EXEC_PATH
  695.         utilargs[0] = SHELL_EXEC_PATH;
  696. #else
  697.         utilargs[0] = "/bin/sh";
  698. #endif
  699.         utilargs[1] = xprintf("%s/mkaliases", smail_util_dir);
  700.         utilargs[2] = NULL;
  701.     }
  702.     child = open_child(utilargs, (char *)NULL, (FILE *)NULL, (FILE *)NULL,
  703.                -1, CHILD_MINENV, getuid(), getgid());
  704.     if (child == -1) {
  705.         if (errfile) {
  706.         fprintf(errfile, "%s: Cannot start %s: %s\n",
  707.             utilargs[0], strerrno(errno));
  708.         }
  709.         exit(EX_UNAVAILABLE);
  710.     }
  711.     close_child((FILE *)NULL, (FILE *)NULL, child);
  712.     exit(0);
  713.     /*NOTREACHED*/
  714.  
  715.     default:
  716.     if (errfile) {
  717.         (void) fprintf(errfile, "%s: option not supported\n", program);
  718.     }
  719.     exitvalue = EX_UNAVAILABLE;
  720.     }
  721.  
  722.     /*
  723.      * all done.
  724.      */
  725.     if (report_memory_usage) {
  726.     if (errfile) {
  727.         (void) fprintf(errfile, "%s: sbrk(0) = %ld\n",
  728.                program, (long)sbrk(0));
  729.     }
  730.     }
  731.     if (force_zero_exitvalue) {
  732.     exit(0);
  733.     }
  734.     exit(exitvalue);
  735. }
  736.  
  737.  
  738. /*
  739.  * initialize_state - set some parameters to their default value
  740.  */
  741. void
  742. initialize_state()
  743. {
  744.     send_to_postmaster = FALSE;
  745.     return_to_sender = FALSE;
  746.     islocal = FALSE;
  747.     exitvalue = EX_OK;
  748.     sender = NULL;
  749.     error_sender = FALSE;
  750.     path_to_sender = NULL;
  751.     sender_name = NULL;
  752.     operation_mode = MODE_DEFAULT;
  753.     process_queue = FALSE;
  754.     queue_interval = 0;
  755.     hop_count = -1;
  756.     do_aliasing = TRUE;
  757.     extract_addresses = FALSE;
  758.     dot_usage = DOT_ENDS_MESSAGE;
  759.     me_too = FALSE;
  760.     error_processing = ERROR_DEFAULT;
  761.     recipients = NULL;
  762.     some_deferred_addrs = FALSE;
  763.     call_defer_message = FALSE;
  764.     sender_is_trusted = TRUE;
  765.     dont_deliver = FALSE;
  766.  
  767.     /*
  768.      * generate a new address hit table where case is ignored and
  769.      * all data resides in memory
  770.      */
  771.     /* XXX - hit_table should be associated with a block */
  772.     hit_table = new_hash_table(hit_table_len,
  773.                    (struct block *)NULL,
  774.                    HASH_DEFAULT);
  775. }
  776.  
  777.  
  778. /*
  779.  * process_args - process the arguments passed to the mailer
  780.  *
  781.  * In general use sendmail semantics, with different argument
  782.  * processing based on name at invocation.
  783.  */
  784. void
  785. process_args(args)
  786.     register char **args;        /* vector of arguments */
  787. {
  788.     struct addr *cur;            /* temp addr list entry */
  789.     char *arg;                /* single string from args */
  790.     char *error;            /* error message */
  791.     char *newsender;            /* temp for process sender */
  792.     static char *end_arg = "";        /* swallow remaining chars in arg */
  793.  
  794.     /*
  795.      * go through the list of arguments in search of options and
  796.      * addresses.
  797.      */
  798.     while (arg = *args++) {
  799.  
  800.     /* option arguments begin with '-', of course */
  801.     if (arg[0] == '-') {
  802.  
  803.         /* switch on each letter */
  804.         arg++;
  805.         while (*arg) switch(*arg++) {
  806.  
  807.         case 'd':            /* set debug level */
  808.         case 'v':            /* verbose, same as debug */
  809.         if (prog_type == PROG_RMAIL || prog_type == PROG_RSMTP) {
  810.             rmail_panic();
  811.         }
  812.         if (arg[0]) {
  813.             char *error = NULL;
  814.  
  815.             debug = (int)c_atol(arg, &error);
  816.             if (error || debug < 0) {
  817.             if (errfile) {
  818.                 (void) fprintf(errfile,
  819.             "%s: -%c flag takes an optional non-negative number\n",
  820.                        program, arg[-1]);
  821.             }
  822.             exit(EX_USAGE);
  823.             }
  824.             arg = end_arg;
  825.         } else {
  826.             debug = 1;        /* if no number, default to 1 */
  827.         }
  828.         break;
  829.  
  830.         case 'D':
  831.         arg_debug_file = arg;
  832.         arg = end_arg;
  833.         if (arg_debug_file[0] == '\0') {
  834.             arg_debug_file = *args++;
  835.             panic_if_null(arg_debug_file, "D");
  836.         }
  837.         if (debug == 0)
  838.             debug = 1;
  839.         break;
  840.  
  841. #ifdef GLOTZNET
  842.         case 'G':
  843.         glotzhost = arg;
  844.         arg = end_arg;
  845.         /* if no string there, take next arg */
  846.         if (sender_name[0] == '\0') {
  847.             glotzhost = *args++;
  848.             panic_if_null(glotzhost, "G");
  849.         }
  850.         break;
  851. #endif /* GLOTZNET */
  852.  
  853.         case 'V':
  854.         operation_mode = PRINT_VERSION;
  855.         break;
  856.  
  857.         case 'F':            /* set full name of sender */
  858.         sender_name = arg;
  859.         arg = end_arg;        /* terminate args in current argv */
  860.         /* if no string there, take next arg */
  861.         if (sender_name[0] == '\0') {
  862.             sender_name = *args++;
  863.             panic_if_null(sender_name, "F");
  864.         }
  865.         break;
  866.  
  867.         case 'r':            /* set path to sender */
  868.         /* SCO Execmail '-r' option not applicable to smail */
  869.         if (prog_type == PROG_EXECMAIL)
  870.             break;
  871.         /* FALL THROUGH */
  872.  
  873.         case 'f':            /* set path to sender */
  874.         newsender = arg;
  875.         arg = end_arg;        /* terminate args in current argv */
  876.         /* if no string there, take next arg */
  877.         if (newsender[0] == '\0') {
  878.             newsender = *args++;
  879.             panic_if_null(newsender, "f");
  880.         }
  881.  
  882.         /*
  883.          * don't use this sender if it has been determined that
  884.          * the local originator of mail is not a user expected
  885.          * to receive remote mail.
  886.          */
  887.         if (sender_is_trusted) {
  888.             sender = newsender;
  889.             /* special form of sender for SMTP error mail */
  890.             if (EQ(sender, "<>")) {
  891.             sender = "MAILER-DAEMON";
  892.             error_sender = TRUE;
  893.             islocal = FALSE;
  894.             } else if (EQ(sender, "<+>")) {
  895.             sender = "MAILER-DAEMON";
  896.             error_sender = TRUE;
  897.             islocal = TRUE;
  898.             } else {
  899.             newsender = preparse_address(sender, &error);
  900.             if (newsender == NULL) {
  901.                 if (errfile) {
  902.                 (void)fprintf(errfile,
  903.                           "%s: error in sender name: %s",
  904.                           program, error);
  905.                 }
  906.                 sender = "MAILER-DAEMON";
  907.                 islocal = FALSE;
  908.             }
  909.             islocal =
  910.                 (parse_address(sender, (char **)0, &error, (int *)0)
  911.                    == LOCAL);
  912.             }
  913.         }
  914.         break;
  915.  
  916.         case 'N':            /* don't deliver message */
  917.         dont_deliver = TRUE;
  918.         break;
  919.  
  920.         case 'C':            /* set config file name */
  921.         if (prog_type == PROG_RMAIL || prog_type == PROG_RSMTP) {
  922.             rmail_panic();
  923.         }
  924.         config_file = arg;
  925.         arg = end_arg;        /* terminate args in current argv */
  926.         /* if no string there, take next arg */
  927.         if (config_file[0] == '\0') {
  928.             config_file = *args++;
  929.             panic_if_null(config_file, "C");
  930.         }
  931.         break;
  932.  
  933.         case 'q':            /* check queue (at interval) */
  934.         if (prog_type == PROG_RMAIL || prog_type == PROG_RSMTP) {
  935.             rmail_panic();
  936.         }
  937.         process_queue = TRUE;
  938.         if (arg[0]) {
  939.             long l = ivaltol(arg);
  940.  
  941.             if (l < 0) {
  942.             if (errfile) {
  943.                 (void) fprintf(errfile,
  944.                        "%s: %s: malformed interval\n",
  945.                        program, arg);
  946.                 exit(EX_USAGE);
  947.             }
  948.             }
  949.             queue_interval = (unsigned)l;
  950.             if (l != queue_interval) {
  951.             (void) fprintf(errfile, "%s: %s: interval too large\n",
  952.                        program, arg);
  953.             exit(EX_USAGE);
  954.             }
  955.             arg = end_arg;    /* uses rest of argument */
  956.         }
  957.         break;
  958.  
  959.         case 'h':            /* hopcount, number is the count */
  960.             {
  961.             char *error = NULL;
  962.  
  963.             if (arg[0]) {
  964.             hop_count = (int)c_atol(arg, &error);
  965.             arg = end_arg;
  966.             } else {
  967.             hop_count = atoi(*args++);
  968.             }
  969.             if (error || hop_count < 0) {
  970.             if (errfile) {
  971.                 (void) fprintf(errfile,
  972.                    "%s: -h flag takes a non-negative number\n",
  973.                        program);
  974.             }
  975.             exit(EX_USAGE);
  976.             }
  977.         }
  978.         break;
  979.  
  980.         case 'n':            /* don't do aliasing */
  981.         if (prog_type == PROG_RMAIL || prog_type == PROG_RSMTP) {
  982.             rmail_panic();
  983.         }
  984.         do_aliasing = FALSE;
  985.         break;
  986.  
  987.         case 't':            /* read recipients from message */
  988.         extract_addresses = TRUE;
  989.         break;
  990.  
  991.         case 'i':            /* don't treat dots specially */
  992.         dot_usage = NO_DOT_PROTOCOL;
  993.         break;
  994.  
  995.         case 'I':            /* use hidden-dot protocol on input */
  996.         dot_usage = HIDDEN_DOTS;
  997.         break;
  998.  
  999.         case 'm':            /* author can be included in alias */
  1000.         me_too = TRUE;
  1001.         break;
  1002.  
  1003.         case 'Q':
  1004.         queue_only = TRUE;    /* spool but do not deliver, yet */
  1005.         break;
  1006.  
  1007.         case 'e':            /* what to do on errors */
  1008.         if (arg[0] == '\0') {
  1009.             arg = *args++;
  1010.             panic_if_null(arg, "e");
  1011.         }
  1012.         switch(*arg) {
  1013.  
  1014.         case 'e':        /* we don't support berkenet */
  1015.         case 'm':        /* mail back errors */
  1016.             error_processing = MAIL_BACK;
  1017.             break;
  1018.         case 'w':        /* send via "write" */
  1019.             error_processing = WRITE_BACK;
  1020.             break;
  1021.         case 'p':        /* print errors on screen */
  1022.             error_processing = TERMINAL;
  1023.             break;
  1024.         case 'q':        /* be quiet about errors */
  1025.             error_processing = DEV_NULL;
  1026.             break;
  1027.         }
  1028.         arg = end_arg;        /* swallows complete argument */
  1029.         break;
  1030.  
  1031.         case 'o':            /* set various option */
  1032.         if (arg[0] == '\0') {
  1033.             arg = *args++;
  1034.             panic_if_null(arg, "o");
  1035.         }
  1036.         switch (*arg++) {
  1037.  
  1038.         case 'i':        /* same as -i */
  1039.             dot_usage = NO_DOT_PROTOCOL;
  1040.             break;
  1041.  
  1042.         case 'A':
  1043.             if (*arg == '\0') {
  1044.             arg = *args++;
  1045.             panic_if_null(arg, "oA");
  1046.             }
  1047.             arg_alias_file = arg;
  1048.             break;
  1049.  
  1050.         case 'I':        /* same as -I */
  1051.             dot_usage = HIDDEN_DOTS;
  1052.             break;
  1053.  
  1054.         case 'U':
  1055.             report_memory_usage = TRUE;
  1056.             break;
  1057.  
  1058.         case 'M':
  1059.             if (*arg == '\0') {
  1060.             arg = *args++;
  1061.             panic_if_null(arg, "oM");
  1062.             }
  1063.             switch (*arg++) {
  1064.             case 's':
  1065.             if (*arg == '\0') {
  1066.                 arg = *args++;
  1067.                 panic_if_null(arg, "oMs");
  1068.             }
  1069.             sender_host = arg;
  1070.             break;
  1071.  
  1072.             case 'a':
  1073.             if (*arg == '\0') {
  1074.                 arg = *args++;
  1075.                 panic_if_null(arg, "oMa");
  1076.             }
  1077.             sender_host_addr = arg;
  1078.             break;
  1079.  
  1080.             case 'r':
  1081.             if (*arg == '\0') {
  1082.                 arg = *args++;
  1083.                 panic_if_null(arg, "oMr");
  1084.             }
  1085.             sender_proto = arg;
  1086.             break;
  1087.  
  1088.             case 'P':
  1089.             if (*arg == '\0') {
  1090.                 arg = *args++;
  1091.                 panic_if_null(arg, "oMP");
  1092.             }
  1093.             sender_program = arg;
  1094.             break;
  1095.             }
  1096.             break;
  1097.  
  1098.         case 'e':        /* same as -eX */
  1099.             if (*arg == '\0') {
  1100.             arg = *args++;
  1101.             panic_if_null(arg, "oe");
  1102.             }
  1103.             switch (*arg) {
  1104.  
  1105.             case 'm':
  1106.             error_processing = MAIL_BACK;
  1107.             break;
  1108.             case 'w':
  1109.             error_processing = WRITE_BACK;
  1110.             break;
  1111.             case 'p':
  1112.             error_processing = TERMINAL;
  1113.             break;
  1114.             case 'q':
  1115.             error_processing = DEV_NULL;
  1116.             break;
  1117.             }
  1118.             break;
  1119.  
  1120.         case 'd':        /* delivery mode */
  1121.             if (prog_type == PROG_RMAIL || prog_type == PROG_RSMTP) {
  1122.             rmail_panic();
  1123.             }
  1124.             if (*arg == '\0') {
  1125.             arg = *args++;
  1126.             panic_if_null(arg, "od");
  1127.             }
  1128.             switch (*arg) {
  1129.  
  1130.             case 'f':
  1131.             deliver_mode = FOREGROUND;
  1132.             break;
  1133.  
  1134.             case 'b':
  1135.             deliver_mode = BACKGROUND;
  1136.             break;
  1137.  
  1138.             case 'q':
  1139.             deliver_mode = QUEUE_MESSAGE;
  1140.             break;
  1141.             }
  1142.             break;
  1143.  
  1144.         case 'C':        /* name of config file */
  1145.             if (prog_type == PROG_RMAIL || prog_type == PROG_RSMTP) {
  1146.             rmail_panic();
  1147.             }
  1148.             if (*arg == '\0') {
  1149.             arg = *args++;
  1150.             panic_if_null(arg, "oC");
  1151.             }
  1152.             config_file = arg;
  1153.             break;
  1154.  
  1155.         case 'L':
  1156.             if (prog_type == PROG_RMAIL || prog_type == PROG_RSMTP) {
  1157.             rmail_panic();
  1158.             }
  1159.             if (*arg == '\0') {
  1160.             arg = *args++;
  1161.             panic_if_null(arg, "oL");
  1162.             }
  1163.             arg_smail_lib_dir = arg;
  1164.             break;
  1165.  
  1166.         case 'S':        /* name of secondary config file */
  1167.             if (prog_type == PROG_RMAIL || prog_type == PROG_RSMTP) {
  1168.             rmail_panic();
  1169.             }
  1170.             if (*arg == '\0') {
  1171.             arg = *args++;
  1172.             panic_if_null(arg, "oS");
  1173.             }
  1174.             arg_second_config_file = arg;
  1175.             break;
  1176.  
  1177.         case 'D':        /* name of director file */
  1178.             if (prog_type == PROG_RMAIL || prog_type == PROG_RSMTP) {
  1179.             rmail_panic();
  1180.             }
  1181.             if (*arg == '\0') {
  1182.             arg = *args++;
  1183.             panic_if_null(arg, "oD");
  1184.             }
  1185.             arg_director_file = arg;
  1186.             break;
  1187.  
  1188.         case 'E':        /* name of retry file */
  1189.             if (prog_type == PROG_RMAIL || prog_type == PROG_RSMTP) {
  1190.             rmail_panic();
  1191.             }
  1192.             if (*arg == '\0') {
  1193.             arg = *args++;
  1194.             panic_if_null(arg, "oE");
  1195.             }
  1196.             arg_retry_file = arg;
  1197.             break;
  1198.  
  1199.         case 'Q':        /* name of qualify file */
  1200.             if (prog_type == PROG_RMAIL || prog_type == PROG_RSMTP) {
  1201.             rmail_panic();
  1202.             }
  1203.             if (*arg == '\0') {
  1204.             arg = *args++;
  1205.             panic_if_null(arg, "oQ");
  1206.             }
  1207.             arg_qualify_file = arg;
  1208.             break;
  1209.  
  1210.         case 'R':        /* name of router file */
  1211.             if (prog_type == PROG_RMAIL || prog_type == PROG_RSMTP) {
  1212.             rmail_panic();
  1213.             }
  1214.             if (*arg == '\0') {
  1215.             arg = *args++;
  1216.             panic_if_null(arg, "oR");
  1217.             }
  1218.             arg_router_file = arg;
  1219.             break;
  1220.  
  1221.         case 'T':        /* name of transport file */
  1222.             if (prog_type == PROG_RMAIL || prog_type == PROG_RSMTP) {
  1223.             rmail_panic();
  1224.             }
  1225.             if (*arg == '\0') {
  1226.             arg = *args++;
  1227.             panic_if_null(arg, "oT");
  1228.             }
  1229.             arg_transport_file = arg;
  1230.             break;
  1231.  
  1232.         case 'X':
  1233.             if (*arg == '\0') {
  1234.             arg = *args++;
  1235.             panic_if_null(arg, "oX");
  1236.             }
  1237.             smtp_service_name = arg;
  1238.             break;
  1239.  
  1240.         case 'm':        /* same as -m */
  1241.             me_too = TRUE;
  1242.             break;
  1243.         }
  1244.         arg = end_arg;
  1245.         break;
  1246.  
  1247.         case 'b':            /* set operating mode */
  1248.         if (*arg == '\0') {
  1249.             arg = *args++;
  1250.             panic_if_null(arg, "b");
  1251.         }
  1252.         switch (*arg) {
  1253.  
  1254.         case 'd':        /* operate as daemon */
  1255.             if (prog_type == PROG_RMAIL || prog_type == PROG_RSMTP) {
  1256.             rmail_panic();
  1257.             }
  1258.             operation_mode = DAEMON_MODE;
  1259.             break;
  1260.  
  1261.         case 'i':        /* initialize aliases database */
  1262.             if (prog_type == PROG_RMAIL || prog_type == PROG_RSMTP) {
  1263.             rmail_panic();
  1264.             }
  1265.             operation_mode = REBUILD_ALIASES;
  1266.             break;
  1267.  
  1268.         case 'm':        /* just deliver mail */
  1269.             operation_mode = DELIVER_MAIL;
  1270.             break;
  1271.  
  1272.         case 'p':        /* print the queue */
  1273.             if (prog_type == PROG_RMAIL || prog_type == PROG_RSMTP) {
  1274.             rmail_panic();
  1275.             }
  1276.             operation_mode = PRINT_QUEUE;
  1277.             break;
  1278.  
  1279.         case 't':        /* run in address test mode */
  1280.             if (prog_type == PROG_RMAIL || prog_type == PROG_RSMTP) {
  1281.             rmail_panic();
  1282.             }
  1283.             operation_mode = TEST_MODE;
  1284.             break;
  1285.  
  1286.         case 'v':        /* verify addresses only */
  1287.             operation_mode = VERIFY_ADDRS;
  1288.             break;
  1289.  
  1290.         case 'V':
  1291.             operation_mode = PRINT_VERSION;
  1292.             break;
  1293.  
  1294.         case 's':        /* process smtp on input */
  1295.             operation_mode = SMTP_MODE;
  1296.             break;
  1297.  
  1298.         case 'S':        /* batched SMTP mode */
  1299.             operation_mode = BATCH_SMTP_MODE;
  1300.             break;
  1301.  
  1302.         case 'z':        /* freeze config file */
  1303.             if (prog_type == PROG_RMAIL || prog_type == PROG_RSMTP) {
  1304.             rmail_panic();
  1305.             }
  1306.             operation_mode = FREEZE_CONFIG;
  1307.             break;
  1308.  
  1309.             case 'R':        /* rogue tombstone mode */
  1310.             operation_mode = ROGUE_MODE;
  1311.             break;
  1312.  
  1313.         case 'c':        /* print COPYING file */
  1314.             operation_mode = COPYING_MODE;
  1315.             break;
  1316.  
  1317.         case 'P':
  1318.             operation_mode = PRINT_VARS_MODE;
  1319.             break;
  1320.         }
  1321.         arg = end_arg;
  1322.         break;
  1323.         }
  1324.     } else {
  1325.  
  1326.         /*
  1327.          * not a flag, arg must be a recipient address so insert
  1328.          * it in the list.
  1329.          */
  1330.         cur = alloc_addr();
  1331.         cur->in_addr = escape_newline(arg);
  1332.         cur->uid = nobody_uid;
  1333.         cur->gid = nobody_gid;
  1334.         cur->succ = recipients;
  1335.         recipients = cur;
  1336.     }
  1337.     }
  1338. }
  1339.  
  1340. static char *
  1341. escape_newline(s)
  1342.     register char *s;
  1343. {
  1344.     struct str str;
  1345.     register struct str *sp = &str;
  1346.     register int c;
  1347.  
  1348.     if (strchr(s, '\n') == NULL)
  1349.     return s;
  1350.     STR_INIT(sp);
  1351.  
  1352.     while (c = *s++) {
  1353.     if (c == '\n')
  1354.         STR_CAT(sp, "\\n");
  1355.     else
  1356.         STR_NEXT(sp, c);
  1357.     }
  1358.     STR_NEXT(sp, '\0');
  1359.     STR_DONE(sp);
  1360.  
  1361.     return sp->p;
  1362. }
  1363.  
  1364. /*
  1365.  * panic_if_null - complain with a usage message if the given pointer is NULL
  1366.  */
  1367. static void
  1368. panic_if_null(p, fl)
  1369.     char *p;
  1370.     char *fl;                /* name of flag to give usage for */
  1371. {
  1372.     if (p == NULL) {
  1373.     if (errfile) {
  1374.         (void) fprintf(errfile, "%s: argument expected after -%s\n",
  1375.                program, fl);
  1376.     }
  1377.     exit(EX_USAGE);
  1378.     }
  1379. }
  1380.  
  1381. /*
  1382.  * rmail_panic - complain about an option not allowed with rmail or rsmtp
  1383.  */
  1384. static void
  1385. rmail_panic()
  1386. {
  1387.     if (errfile) {
  1388.     (void) fprintf(errfile,
  1389.                "%s: usage with rmail and rsmtp is restricted\n",
  1390.                program);
  1391.     }
  1392.     exit(EX_USAGE);
  1393. }
  1394.